package ThreadPool;

import java.util.concurrent.*;

/**
 * 线程池代码演示
 */
public class ThreadPoolDemo {
    public static void main(String[] args) {

//        System.out.println("=======Fixed Thread Pool========");
//        // ⼀个池⼦有5个⼯作线程，类似银⾏有5个受理窗⼝【定长线程池】
//        threadPoolTask(Executors.newFixedThreadPool(5));
//
//        try {
//            TimeUnit.SECONDS.sleep(5);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }
//
//        System.out.println("======Single Thread Pool=========");
//        // ⼀个池⼦有1个⼯作线程，类似银⾏有1个受理窗⼝【单一长度线程池】
//        threadPoolTask(Executors.newSingleThreadExecutor());
//
//        try {
//            TimeUnit.SECONDS.sleep(10);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }
//
//        System.out.println("=====Cached Thread Pool=======");
//        // 不定量线程，⼀个池⼦有N个⼯作线程，类似银⾏有N个受理窗⼝【变长线程池】
//        threadPoolTask(Executors.newCachedThreadPool());
//
//        try {
//            TimeUnit.SECONDS.sleep(5);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }

        /**
         * corePoolSize 线程池中的常驻核⼼线程数
         * maximumPoolSize 线程池中能够容纳同时指向的最⼤线程数，此值必须⼤于等于1
         * keepAliveTime 多余的空闲线程的存活时间【非核心线程的保活时间】，当前池中线程数量超过corePoolSize时，当空闲时间达到keepAliveTime时，多余线程会被销毁直到只剩下corePoolSize个线程为⽌
         * unit keepAliveTime存活时间的单位
         * workQueue 任务队列，存放已提交但尚未执⾏的任务
         * threadFactory 表示⽣成线程池中⼯作线程的线程⼯⼚，⽤于创建线程，⼀般默认的即可
         * handler 拒绝策略，表示当队列满了，并且⼯作线程⼤于等于线程池的最⼤线程数（maximumPoolSize）时，如何来拒绝请求执⾏的runnable的策略
         *
         * 线程池工作流程：
         * 先用核心线程处理任务，核心线程用完时，先将新任务放在任务队列中，当任务队列也满了时，启动非核心线程来处理任务，当线程池中的线程数达到最大时，根据拒绝策略拒绝新任务
         *
         */

        /**
         * JDK提供了四种拒绝策略，分别是。
         * 1. AbortPolicy：默认的策略，直接抛出 RejectedExecutionException 异常，阻⽌系统正常运⾏。
         * 2. CallerRunsPolicy：既不会抛出异常，也不会终⽌任务，⽽是将任务返回给调⽤者【让调用者来执行该任务】，从⽽降低新任务的流量。
         * 3. DiscardOldestPolicy：抛弃队列中等待最久的任务，然后把当前任务加⼊队列中尝试再次提交任务。
         * 4. DiscardPolicy：该策略默默地丢弃⽆法处理的任务，不予任何处理也不抛出异常。如果允许任务丢失，这是最好的⼀种策略。
         */
        System.out.println("=====Custom Thread Pool=======");
        // 自定义线程池
        threadPoolTask(new ThreadPoolExecutor(
                2,
                3,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        ));
    }

    private static void threadPoolTask(ExecutorService threadPool) {
        //模拟有10个顾客来办理业务
        try {
            for (int i = 1; i <= 10; i++) {
                // 使用execute来往线程池中添加新任务
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t办理业务");
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}